/*
 * Copyright © 2009 Gerald Isaac Schwarz
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package base;

import java.io.*;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

public class GameSaver {
	private File file;
	private PrintWriter printWriter;
	private Document document;
	private ArrayList<Player> players;
	private Player currentPlayer;
//	private Engine engine;
	private Board board;
	
	public GameSaver(Board board, File file) {
		this.file = file;
		this.board = board;
		this.players = this.board.getPlayers();
		this.currentPlayer = this.board.getCurrentPlayer();
		
		if (this.file.exists()) {
			throw new RuntimeException("Specified file already exists.");
		}
		
		try {
			this.file.createNewFile();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		try {
			this.printWriter = new PrintWriter(this.file);
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		try {
			this.getDocument();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		try {
			this.saveGame();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private void printNodeContent(Node node) throws IOException {
		this.printWriter.print("<" + node.getNodeName());
		if (node.hasAttributes()) {
			for (int i = 0; i < node.getAttributes().getLength(); i++) {
				this.printWriter.print(" ");
				this.printWriter.print(node.getAttributes().item(i).getNodeName() + "=");
				this.printWriter.print("\"" + node.getAttributes().item(i).getNodeValue() + "\"");
			}
		}
		this.printWriter.write(">");
		
		if (node.hasChildNodes()) {
			this.printWriter.println();
			for (int i = 0; i < node.getChildNodes().getLength(); i++) {
				if (node.getChildNodes().item(i).getNodeType() == Node.TEXT_NODE) {
					this.printWriter.print("\t");
					this.printWriter.print(node.getChildNodes().item(i).getTextContent());
					this.printWriter.println();
				}
				else {
					printNodeContent(node.getChildNodes().item(i));
				}
			}
		}
		this.printWriter.print("</" + node.getNodeName() + ">");
		this.printWriter.println();
	}
	
	private void saveCurrentPlayer() {
		Element currentPlayerNode = document.createElement("current_player");
		currentPlayerNode.appendChild(document.createTextNode(this.currentPlayer.getId() + ""));
		document.getDocumentElement().appendChild(currentPlayerNode);
	}
	
	private void savePlayers() {
		for (Player player : this.players) {
			Element playerNode = this.document.createElement("player");
			playerNode.setAttribute("id", player.getId() + "");
			playerNode.setAttribute("name", player.getName());
			playerNode.setAttribute("color", player.getColor().getRGB() + "");
			
			this.document.getDocumentElement().appendChild(playerNode);
		}
	}
	
	private void saveBoard() {
		Board board = this.board;
		Element boardNode = this.document.createElement("board");
		boardNode.setAttribute("width", board.getSize().width + "");
		boardNode.setAttribute("height", board.getSize().height + "");
		
		for (Piece piece : board.getPieces()) {
			Element pieceNode = this.document.createElement("piece");
			pieceNode.setAttribute("level", this.board.getCurrentState(piece).getLevel() + "");
			pieceNode.setAttribute("owner", this.board.getCurrentState(piece).getOwner().getId() + "");
			pieceNode.setAttribute("x", this.board.getCurrentState(piece).getLocation().x + "");
			pieceNode.setAttribute("y", this.board.getCurrentState(piece).getLocation().y + "");
			
			boardNode.appendChild(pieceNode);
		}
		
		this.document.getDocumentElement().appendChild(boardNode);
	}
	
	private void saveGame() throws IOException {
		this.saveCurrentPlayer();
		this.savePlayers();
		this.saveBoard();
		
		this.printWriter.println("<?xml version=\"1.0\"?>");
		this.printWriter.println("<!DOCTYPE saved_game [");
		this.printWriter.println("<!ELEMENT saved_game (current_player, player+, board)>");
		this.printWriter.println("<!ELEMENT current_player (#PCDATA)>");
		this.printWriter.println("<!ELEMENT player EMPTY>");
		this.printWriter.println("<!ATTLIST player id CDATA #REQUIRED>");
		this.printWriter.println("<!ATTLIST player name CDATA #REQUIRED>");
		this.printWriter.println("<!ATTLIST player color CDATA #REQUIRED>");
		this.printWriter.println("<!ELEMENT board (piece+)>");
		this.printWriter.println("<!ATTLIST board width CDATA #REQUIRED>");
		this.printWriter.println("<!ATTLIST board height CDATA #REQUIRED>");
		this.printWriter.println("<!ELEMENT piece EMPTY>");
		this.printWriter.println("<!ATTLIST piece level CDATA #REQUIRED>");
		this.printWriter.println("<!ATTLIST piece owner CDATA #REQUIRED>");
		this.printWriter.println("<!ATTLIST piece x CDATA #REQUIRED>");
		this.printWriter.println("<!ATTLIST piece y CDATA #REQUIRED>");
		this.printWriter.println("]>");
		
		this.printNodeContent(this.document.getDocumentElement());
		
		this.printWriter.flush();
		this.printWriter.close();
	}
	
	private void getDocument() throws IOException, SAXException, ParserConfigurationException {
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		dbf.setValidating(true);
//		dbf.setNamespaceAware(true);
		dbf.setIgnoringElementContentWhitespace(true);
		this.document = dbf.newDocumentBuilder().newDocument();
		
		Element documentElement= document.createElement("saved_game");
		document.appendChild(documentElement);
	}
	
	
}